using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;

namespace AduSkin.Controls.Tools.Interop
{
   internal static class HandleCollector
   {
      private static HandleType[] HandleTypes;
      private static int HandleTypeCount;

      private static readonly object HandleMutex = new object();

      internal static IntPtr Add(IntPtr handle, int type)
      {
         HandleTypes[type - 1].Add();
         return handle;
      }

      [System.Security.SecuritySafeCritical]
      internal static SafeHandle Add(SafeHandle handle, int type)
      {
         HandleTypes[type - 1].Add();
         return handle;
      }

      internal static void Add(int type)
      {
         HandleTypes[type - 1].Add();
      }

      internal static int RegisterType(string typeName, int expense, int initialThreshold)
      {
         lock (HandleMutex)
         {
            if (HandleTypeCount == 0 || HandleTypeCount == HandleTypes.Length)
            {
               HandleType[] newTypes = new HandleType[HandleTypeCount + 10];
               if (HandleTypes != null)
               {
                  Array.Copy(HandleTypes, 0, newTypes, 0, HandleTypeCount);
               }
               HandleTypes = newTypes;
            }

            HandleTypes[HandleTypeCount++] = new HandleType(expense, initialThreshold);
            return HandleTypeCount;
         }
      }

      internal static IntPtr Remove(IntPtr handle, int type)
      {
         HandleTypes[type - 1].Remove();
         return handle;
      }

      [System.Security.SecuritySafeCritical]
      internal static SafeHandle Remove(SafeHandle handle, int type)
      {
         HandleTypes[type - 1].Remove();
         return handle;
      }

      internal static void Remove(int type)
      {
         HandleTypes[type - 1].Remove();
      }

      private class HandleType
      {
         private readonly int _initialThreshHold;
         private int _threshHold;
         private int _handleCount;
         private readonly int _deltaPercent;

         internal HandleType(int expense, int initialThreshHold)
         {
            _initialThreshHold = initialThreshHold;
            _threshHold = initialThreshHold;
            _deltaPercent = 100 - expense;
         }

         internal void Add()
         {
            lock (this)
            {
               _handleCount++;
               var performCollect = NeedCollection();

               if (!performCollect)
               {
                  return;
               }
            }

            GC.Collect();

            var sleep = (100 - _deltaPercent) / 4;
            System.Threading.Thread.Sleep(sleep);
         }

         private bool NeedCollection()
         {

            if (_handleCount > _threshHold)
            {
               _threshHold = _handleCount + _handleCount * _deltaPercent / 100;
               return true;
            }

            var oldThreshHold = 100 * _threshHold / (100 + _deltaPercent);
            if (oldThreshHold >= _initialThreshHold && _handleCount < (int)(oldThreshHold * .9F))
            {
               _threshHold = oldThreshHold;
            }

            return false;
         }

         internal void Remove()
         {
            lock (this)
            {
               _handleCount--;

               _handleCount = Math.Max(0, _handleCount);
            }
         }
      }
   }
}
